開発環境で使うDocker入門
モバイルアプリサービス部の五十嵐です。
Dockerは軽量でポータビリティに優れ、環境を汚さないので開発環境には無くてはならない存在ですよね!今回はまだDockerを使っていない人向けに、私が自分が辿ってきた経験を元に、『こういうシーンでDockerを使うと便利』というのをステップ・バイ・ステップで説明していきます。
対象読者
Dockerはなんとなく知っていて興味はあるけど、使い所や導入するメリットが分からないという人を対象にしています。
環境
- Docker for Mac(Docker 1.12.3)
Dockerについて
Dockerは複数のコンポーネントからなるプラットフォームですが、本記事では主にDocker EngineのことをDockerと呼びます。 Dockerはコンテナと呼ばれる仮想化技術を用いています。従来の仮想化技術と異なる点は、ホストのカーネルをコンテナと共有し、ホストOS上で独立したプロセスとして実行されるという点です。これにより軽量化・高速化が図られています。また、Dockerは特定のインフラに依存せず、Linux・Mac・Windowsなど様々なOS上で動作することができ、ポータビリティに優れています。
初めての人のための記事
初めてDockerを使うという人は、まずは以下の記事を一読されると良いと思います。
- Public BetaになったDocker for Macを使ってみる | Developers.IO
これからDockerをインストールするのであればDocker for Macが良いです。また既にDockerToolboxをインストールされている方も、Docker for Macにすることをオススメします。DockerToolboxのDockerイメージはマイグレーションしてくれます。 -
公式チュートリアルで始めるDocker | Developers.IO
基本的なコマンドなどは以下の記事を参照してください。
Step.1 公開されているイメージを使う
一番簡単な利用例としては、Docker Hub というDockerイメージのリポジトリサービスで公開されているイメージを利用する方法です。
例えば、あるプロジェクトでは MySQL5.6 を利用していてローカルマシンに MySQL5.6 をインストールして開発をしていましたが、次のプロジェクトでは MySQL5.7 を利用することになったとします。ローカルマシンに MySQL5.6/5.7 を両方インストールして必要に応じてサービスを切り替えて利用するのは骨の折れる作業だと思います。
そこでDockerの出番です。MySQLのようなメジャーなサービスであれば Docker Hub でイメージが公開されてるので、それをpullしてローカルマシン上で起動することですぐに必要なミドルウェアを構築することができます。
# MySQL5.6の起動・停止 docker pull mysql:5.6 docker run -d -e MYSQL_ROOT_PASSWORD=password --name mysql5.6 mysql:5.6 docker stop mysql5.6 # MySQL5.7の起動・停止 docker pull mysql:5.7 docker run -d -e MYSQL_ROOT_PASSWORD=password --name mysql5.7 mysql:5.7 docker stop mysql5.7
公開されているリポジトリのうちDocker社が公式として公開しているものには official と書かれています。それ以外にも一般ユーザが公開しているリポジトリもたくさんあります。
また最近ではDocker StoreというDockerイメージのマーケットプレイスでも提供されているようです。
Step.2 自分でイメージを作成して使う
次に自分でイメージを作成する例を紹介します。
例えばローカル開発用に対向システムのWebAPIのモックをRubyで作成したとします。プロジェクトでは数人のメンバーが共同で開発しているため、このモックをメンバー全員が使えるようにする必要があります。ところが各メンバーのローカル環境のRubyバージョンはばらばらで環境構築からする必要があります。
そこでDockerの出番です。Dockerfileを作成して作成したモックアプリケーションを配布可能な状態にします。実際には公開されているイメージをベースにしてカスタマイズしていくことになります。
以下はSinatraで作ったRubyアプリケーションをDockerfileでイメージ化した例です。
アプリケーションのコードはこれだけです。アクセスされたパスに対応する静的なJSONをレスポンスとして返します。
require 'sinatra' require "sinatra/json" require 'json' get '/sample.json' do json get_json("response/sample.json") end def get_json(path) File.open(path) do |file| JSON.load(file) end end
次にDockerfileです。
FROM
に設定するのがベースとなるイメージです。詳細は端折りますがアプリケーションコードをコンテナ内に COPY し、gemをインストールしてrubyアプリケーションを起動しています。モックAPIのレスポンスは静的ファイルになっており、利用者が編集したいのでホストのボリュームにマウントすることにします。
内容と関係ないのですが地味にハマったのはsinatraアプリケーションはdevelopment環境起動では外部からのアクセスを受け付けないようになっているので -o 0.0.0.0
で外部からのアクセスを許可するようにするオプションが必要なことでした。
FROM ruby:2.3.2 WORKDIR /app COPY app.rb /app/app.rb RUN mkdir /app/response RUN gem 'sinatra' RUN gem 'sinatra-contrib' EXPOSE 80 CMD ["ruby", "app.rb", "-p", "80", "-o", "0.0.0.0"]
Dockerfileからイメージを作成するには docker build
コマンドを実行します。
docker build -t mock-api . docker run -d -p 8080:80 -v ./response:/app/response mock-api
作成したDockerfileをGitHubなどで共有すればメンバーへの展開も容易です。以下のイメージでは、DockerfileをGitHubへpushし、別のメンバーがDockerfileをpullしてイメージをビルドし実行する流れを示しています。
Step.3 イメージを組み合わせて使う
次にDocker同士をネットワークで接続したい場合についてです。例としては以前に書いたエントリー
AWS Elasticsearch Serviceと同じバージョンの環境をDockerで作る方法 | Developers.IO
の中でElasticsearchとKibanaを別々のコンテナとして起動し、KibanaのコンテナからElasticsearchのコンテナに接続する例を紹介しました。
docker run
コマンドを実行時にオプションで --link [接続したいイメージ]
を設定することでDocker同士をネットワークで接続した状態にすることができます。
Step.4 アプリケーション本体もDockerで起動する
さらに、アプリケーション本体もDockerコンテナとして起動することでアプリケーションに依存するミドルウェアもコンテナに含めることができますし、他のリソース(MySQLやmock-apiなど)とlinkさせることで、ホスト側にバインドされるポートはアプリケーション本体だけで済むのでホストマシン上でのポートの競合が少なくなり幸せになれそうです。
やることとしては、Step.2 と同じ要領でアプリケーション本体をイメージ化するためのDockerfileを作ってコンテナとして起動して、Step.3 と同様に必要なリソースとlinkさせるだけです。
Step.5 DockerComposeで構成管理をする
さて、Dockerに慣れてくると1つのプロジェクトでいくつものDockerコンテナを利用する状態になってきます。MySQL、Elasticsearch、Kibana、Redis、DynamoDB、fakeS3、fakesmtpなどが起動しています。しかもそれがプロジェクトごとにあります。
こうしたいくつものDockerコンテナをまとめて管理できるコンポーネントとしてDocker Composeがあります。Docker Composeは docker-compose.yml
という設定ファイルを書くことで複数のDockerコンテナをまとめて管理することできます。
例として実際に使っている docker-compose.yml
からいくつかの設定をピックアップしました。Dockerの色々なコマンドを設定ファイルとして記述できるものと思ってもらえれば良いと思います。Dockerfileからイメージの作成する場合は、 build:
にDockerfileのパスを書けばビルドから起動まで1コマンドでやってくれます。
# MySQL mysql57: image: mysql:5.7 ports: - 3306:3306 environment: - MYSQL_ROOT_PASSWORD=password - TZ=JST # Elasticsearch1.5 elasticsearch: image: elasticsearch:1.5 ports: - 9200:9200 - 9300:9300 # Kibana4.0.3 kibana: image: kibana:4.0.3 ports: - 5601:5601 environment: - ELASTICSEARCH_URL=http://elasticsearch:9200 links: - elasticsearch # Mock API mock-api: build: ./mock/api ports: - "8080:80" volumes: - ./mock/api/response:/app/response
docker-compose.yml
ファイルがあるディレクトリで docker-compose
コマンドを実行してコンテナを起動・停止します。
# 全てのコンテナを起動 docker-compose up -d # 全てのコンテナを停止 docker-compose stop
まとめ
私が実際に利用しているパターンを紹介しました。まだDockerを導入していないという人は是非使ってみてください。開発環境の構築にかかる時間が劇的に減りますよ!
また今後は、本番環境でもDocker(AWS ECS)を使っていきたいと考えているので、本番環境で使う上で必要なことを調査していきたいと思います。